001 /* 002 * Copyright 2005-2006 Stephen J. McConnell 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.library.impl; 020 021 import java.io.File; 022 import java.util.Arrays; 023 import java.util.ArrayList; 024 import java.util.List; 025 import java.util.regex.Pattern; 026 import java.util.regex.Matcher; 027 import java.util.Properties; 028 import java.util.Hashtable; 029 import java.util.Map; 030 031 import net.dpml.library.info.Scope; 032 import net.dpml.library.info.AbstractDirective; 033 import net.dpml.library.info.ModuleDirective; 034 import net.dpml.library.info.ResourceDirective; 035 import net.dpml.library.info.DependencyDirective; 036 import net.dpml.library.info.ResourceDirective.Classifier; 037 import net.dpml.library.info.TypeDirective; 038 import net.dpml.library.info.InfoDirective; 039 import net.dpml.library.Module; 040 import net.dpml.library.Resource; 041 import net.dpml.library.ResourceNotFoundException; 042 import net.dpml.library.ModuleNotFoundException; 043 044 import net.dpml.lang.Category; 045 import net.dpml.lang.DuplicateKeyException; 046 047 /** 048 * A Module is a collection of resources. It serves to establish a 049 * namespace and a framework for sharing properties and characteristics 050 * defined within within the module with resources contained within the 051 * module. 052 * 053 * @author <a href="http://www.dpml.net">The Digital Product Meta Library</a> 054 * @version 1.0.0 055 */ 056 public final class DefaultModule extends DefaultResource implements Module 057 { 058 private final boolean m_root; 059 private final ModuleDirective m_directive; 060 private final Map m_map = new Hashtable(); 061 062 /** 063 * Constructor used by the library to create a virtual root module os shared 064 * resource references. 065 * @param logger the assigned logging channel 066 * @param library the library 067 * @param directive the directive from which common properties are established 068 */ 069 DefaultModule( final DefaultLibrary library, final AbstractDirective directive ) 070 { 071 super( library, directive ); 072 073 m_root = true; 074 m_directive = null; 075 } 076 077 /** 078 * Creation of a new nested module. 079 * @param logger the assigned logging channel 080 * @param library the library 081 * @param module the parent module 082 * @param directive the directive from which common properties are established 083 */ 084 DefaultModule( 085 final DefaultLibrary library, final DefaultModule module, final ModuleDirective directive ) 086 throws DuplicateKeyException 087 { 088 super( library, module, directive ); 089 090 m_root = false; 091 m_directive = directive; 092 ResourceDirective[] directives = directive.getResourceDirectives(); 093 for( int i=0; i<directives.length; i++ ) 094 { 095 ResourceDirective res = directives[i]; 096 addResource( res ); 097 } 098 } 099 100 /** 101 * Add a resource to the module. 102 * @param directive the resource directive to add to the module 103 * @throws DuplicateKeyException if a resource name is already bound 104 */ 105 DefaultResource addResource( final ResourceDirective directive ) throws DuplicateKeyException 106 { 107 if( null == directive ) 108 { 109 throw new NullPointerException( "directive" ); 110 } 111 112 synchronized( m_map ) 113 { 114 String key = directive.getName(); 115 if( m_map.containsKey( key ) ) 116 { 117 if( directive instanceof ModuleDirective ) 118 { 119 DefaultModule module = (DefaultModule) m_map.get( key ); 120 121 // check basedir values 122 123 if( null != directive.getBasedir() ) 124 { 125 if( null != module.getBaseDir() ) 126 { 127 File base = new File( getBaseDir(), directive.getBasedir() ); 128 if( !module.getBaseDir().equals( base ) ) 129 { 130 final String error = 131 "Cannot merge modules with different base directories." 132 + "\nModule: " + module 133 + "\nPrimary base: " + module.getBaseDir() 134 + "\nSecondary base: " + base; 135 throw new IllegalStateException( error ); 136 } 137 } 138 } 139 140 // check versions 141 142 if( null != directive.getVersion() ) 143 { 144 if( module.getVersion().equals( directive.getVersion() ) ) 145 { 146 final String error = 147 "Cannot merge modules with different versions." 148 + "\nModule: " + module 149 + "\nPrimary version: " + module.getVersion() 150 + "\nSecondary version: " + directive.getVersion(); 151 throw new IllegalStateException( error ); 152 } 153 } 154 155 // check types 156 157 if( directive.getTypeDirectives().length > 0 ) 158 { 159 final String error = 160 "Cannot merge a module with type production directives." 161 + "\nModule: " + module; 162 throw new IllegalStateException( error ); 163 } 164 165 // check dependencies 166 167 if( directive.getDependencyDirectives().length > 0 ) 168 { 169 final String error = 170 "Cannot merge a module with dependency directives." 171 + "\nModule: " + module; 172 throw new IllegalStateException( error ); 173 } 174 175 // add additional resources 176 177 ModuleDirective d = (ModuleDirective) directive; 178 ResourceDirective[] resources = d.getResourceDirectives(); 179 for( int i=0; i<resources.length; i++ ) 180 { 181 ResourceDirective r = resources[i]; 182 module.addResource( r ); 183 } 184 return module; 185 } 186 else 187 { 188 throw new DuplicateKeyException( key ); 189 } 190 } 191 else 192 { 193 DefaultLibrary library = getDefaultLibrary(); 194 if( directive instanceof ModuleDirective ) 195 { 196 ModuleDirective d = (ModuleDirective) directive; 197 DefaultModule module = new DefaultModule( library, this, d ); 198 m_map.put( key, module ); 199 return module; 200 } 201 else 202 { 203 DefaultResource resource = new DefaultResource( library, this, directive ); 204 m_map.put( key, resource ); 205 return resource; 206 } 207 } 208 } 209 } 210 211 //---------------------------------------------------------------------------- 212 // Module 213 //---------------------------------------------------------------------------- 214 215 /** 216 * Return an array of immediate resources contained within the 217 * module. 218 * @return the resource array 219 */ 220 public Resource[] getResources() 221 { 222 return getDefaultResources(); 223 } 224 225 /** 226 * Return a resource using a supplied name. 227 * @param ref a path relative to the module 228 * @return the resource array 229 * @exception ResourceNotFoundException if the resource does not exist 230 */ 231 public Resource getResource( final String ref ) throws ResourceNotFoundException 232 { 233 try 234 { 235 return getDefaultResource( ref ); 236 } 237 catch( InvalidNameException e ) 238 { 239 final String error = 240 "Resource reference [" 241 + ref 242 + "] is undefined."; 243 throw new ResourceNotFoundException( error, e ); 244 } 245 } 246 247 /** 248 * Return the array of modules that are direct children of this module. 249 * @return the child modules 250 */ 251 public Module[] getModules() 252 { 253 return getDefaultModules(); 254 } 255 256 /** 257 * Return a module using a supplied reference. 258 * @param ref a path relative to the module 259 * @return the module array 260 * @exception ModuleNotFoundException if the module does not exist 261 */ 262 public Module getModule( final String ref ) throws ModuleNotFoundException 263 { 264 try 265 { 266 return getDefaultModule( ref ); 267 } 268 catch( InvalidNameException e ) 269 { 270 final String error = 271 "Cannot locate module [" 272 + ref 273 + "] within module [" 274 + getResourcePath() 275 + "]"; 276 throw new ModuleNotFoundException( error, e ); 277 } 278 } 279 280 /** 281 * Return the array of modules that are descendants of this module. 282 * @return the descendants module array 283 */ 284 public Module[] getAllModules() 285 { 286 return getAllDefaultModules(); 287 } 288 289 /** 290 * <p>Select a set of resource matching a supplied a resource selection 291 * constraint. The constraint may contain the wildcards '**' and '*'. 292 * @param criteria the selection criteria 293 * @param local if true limit the selection to local projects 294 * @param sort if true the returned array will be sorted relative to dependencies 295 * otherwise the array will be sorted alphanumerically 296 * @return an array of resources matching the selection criteria 297 */ 298 public Resource[] select( final String criteria, final boolean local, final boolean sort ) 299 { 300 DefaultResource[] resources = selectDefaultResources( local, criteria ); 301 if( sort ) 302 { 303 return sortDefaultResources( resources, Scope.TEST ); 304 } 305 else 306 { 307 Arrays.sort( resources ); 308 return resources; 309 } 310 311 } 312 313 /** 314 * Locate a resource relative to a base directory. 315 * @param base the base directory 316 * @return a resource with a matching basedir 317 * @exception ResourceNotFoundException if resource match relative to the supplied base 318 */ 319 public Resource locate( final File base ) throws ResourceNotFoundException 320 { 321 DefaultResource[] resources = selectDefaultResources( true, "**/*" ); 322 for( int i=0; i<resources.length; i++ ) 323 { 324 DefaultResource resource = resources[i]; 325 File basedir = resource.getBaseDir(); 326 if( ( null != basedir ) && base.equals( basedir ) ) 327 { 328 return resource; 329 } 330 } 331 throw new ResourceNotFoundException( base.toString() ); 332 } 333 334 /** 335 * Return a directive suitable for publication as an external description. 336 * @return the resource directive 337 */ 338 public ModuleDirective export() 339 { 340 if( null == m_directive ) 341 { 342 final String error = 343 "Cannot export from the virtual root."; 344 throw new UnsupportedOperationException( error ); 345 } 346 347 DefaultModule parent = getDefaultParent(); 348 if( null == parent ) 349 { 350 // 351 // exporting a top-level module 352 // 353 354 return (ModuleDirective) exportResource( this ); 355 } 356 else 357 { 358 // 359 // exporting the nested module 360 // 361 362 String path = getResourcePath(); 363 return exportModule( this, path ); 364 } 365 } 366 367 /** 368 * Return a directive suitable for publication as an external description. 369 * @param module the enclosing module 370 * @return the resource directive 371 * @exception IllegalArgumentException if the module is not a top-level module 372 */ 373 ResourceDirective exportResource( final DefaultModule module ) throws IllegalArgumentException 374 { 375 String name = getName(); 376 return exportModule( module, name ); 377 } 378 379 /** 380 * Return a directive suitable for publication as an external description. 381 * @param module the enclosing module 382 * @return the resource directive 383 * @exception IllegalArgumentException if the module is not a top-level module 384 */ 385 ModuleDirective exportModule( final DefaultModule module, final String name ) throws IllegalArgumentException 386 { 387 DefaultResource[] resources = getDefaultResources(); 388 ResourceDirective[] directives = new ResourceDirective[ resources.length ]; 389 for( int i=0; i<directives.length; i++ ) 390 { 391 DefaultResource resource = resources[i]; 392 directives[i] = resource.exportResource( module ); 393 } 394 String version = getVersion(); 395 String basedir = null; 396 InfoDirective info = m_directive.getInfoDirective(); 397 TypeDirective[] types = m_directive.getTypeDirectives(); 398 TypeDirective[] exportedTypes = createExportedTypes( types ); 399 Properties properties = getExportProperties(); 400 return new ModuleDirective( 401 name, version, Classifier.EXTERNAL, basedir, 402 info, exportedTypes, new DependencyDirective[0], 403 directives, properties, null ); 404 } 405 406 //---------------------------------------------------------------------------- 407 // Object 408 //---------------------------------------------------------------------------- 409 410 /** 411 * Return the string representation of the module. 412 * @return the string value 413 */ 414 public String toString() 415 { 416 return toString( "module" ); 417 } 418 419 //---------------------------------------------------------------------------- 420 // DefaultResource (overriding) 421 //---------------------------------------------------------------------------- 422 423 DefaultResource[] getLocalDefaultProviders( final Scope scope, final Category category ) 424 { 425 DefaultResource[] local = super.getLocalDefaultProviders( scope, category ); 426 if( Scope.BUILD.equals( scope ) ) 427 { 428 ArrayList stack = new ArrayList(); 429 for( int i=0; i<local.length; i++ ) 430 { 431 DefaultResource resource = local[i]; 432 stack.add( resource ); 433 } 434 return expandLocalDefaultProviders( stack ); 435 } 436 else if( Scope.RUNTIME.equals( scope ) ) 437 { 438 ArrayList stack = new ArrayList(); 439 for( int i=0; i<local.length; i++ ) 440 { 441 DefaultResource resource = local[i]; 442 stack.add( resource ); 443 } 444 445 DefaultResource[] resources = getDefaultResources(); 446 for( int i=0; i<resources.length; i++ ) 447 { 448 DefaultResource resource = resources[i]; 449 if( !stack.contains( resource ) ) 450 { 451 stack.add( resource ); 452 } 453 } 454 return (DefaultResource[]) stack.toArray( new DefaultResource[0] ); 455 } 456 else 457 { 458 return local; 459 } 460 } 461 462 DefaultResource[] expandLocalDefaultProviders( final List stack ) 463 { 464 DefaultResource[] resources = getDefaultResources(); 465 for( int i=0; i<resources.length; i++ ) 466 { 467 DefaultResource resource = resources[i]; 468 if( resource instanceof DefaultModule ) 469 { 470 DefaultModule module = (DefaultModule) resource; 471 String path = module.getResourcePath(); 472 if( !path.startsWith( getResourcePath() ) ) 473 //if( !getResourcePath().startsWith( path ) ) 474 { 475 DefaultResource[] providers = module.expandLocalDefaultProviders( stack ); 476 for( int j=0; j<providers.length; j++ ) 477 { 478 DefaultResource r = providers[j]; 479 if( !stack.contains( r ) ) 480 { 481 stack.add( r ); 482 } 483 } 484 } 485 } 486 else 487 { 488 DefaultResource[] providers = 489 resource.getAggregatedDefaultProviders( Scope.TEST, true, false ); 490 getParentModules( stack, providers ); 491 } 492 } 493 return (DefaultResource[]) stack.toArray( new DefaultResource[0] ); 494 } 495 496 private void getParentModules( final List stack, final DefaultResource[] resources ) 497 { 498 for( int i=0; i<resources.length; i++ ) 499 { 500 DefaultResource resource = resources[i]; 501 if( !resource.isAnonymous() ) 502 { 503 DefaultModule parent = resource.getDefaultParent(); 504 if( null != parent ) 505 { 506 String path = parent.getResourcePath(); 507 if( !path.startsWith( getResourcePath() ) && !stack.contains( parent ) ) 508 { 509 stack.add( parent ); 510 } 511 } 512 } 513 } 514 } 515 516 void sortDefaultResource( 517 final List visited, final List stack, final Scope scope, final DefaultResource[] resources ) 518 { 519 if( visited.contains( this ) ) 520 { 521 return; 522 } 523 524 visited.add( this ); 525 DefaultResource[] providers = 526 getAggregatedDefaultProviders( scope, false, false ); 527 for( int i=0; i<providers.length; i++ ) 528 { 529 DefaultResource provider = providers[i]; 530 if( isaMember( resources, provider ) ) 531 { 532 provider.sortDefaultResource( visited, stack, scope, resources ); 533 } 534 } 535 536 DefaultModule[] modules = getProviderModules( scope ); 537 for( int i=0; i<modules.length; i++ ) 538 { 539 DefaultResource module = modules[i]; 540 if( isaMember( resources, module ) ) 541 { 542 module.sortDefaultResource( visited, stack, scope, resources ); 543 } 544 } 545 546 if( !stack.contains( this ) ) 547 { 548 stack.add( this ); 549 } 550 } 551 552 //---------------------------------------------------------------------------- 553 // root semantics 554 //---------------------------------------------------------------------------- 555 556 boolean isRoot() 557 { 558 return m_root; 559 } 560 561 //---------------------------------------------------------------------------- 562 // resource and module lookup 563 //---------------------------------------------------------------------------- 564 565 DefaultResource[] getDefaultResources() 566 { 567 return (DefaultResource[]) m_map.values().toArray( new DefaultResource[0] ); 568 } 569 570 DefaultResource getDefaultResource( final String ref ) 571 { 572 if( null == ref ) 573 { 574 throw new NullPointerException( "ref" ); 575 } 576 int n = ref.indexOf( "/" ); 577 if( n > 0 ) 578 { 579 String pre = ref.substring( 0, n ); 580 String post = ref.substring( n+1 ); 581 DefaultModule module = getDefaultModule( pre ); 582 return module.getDefaultResource( post ); 583 } 584 else 585 { 586 DefaultResource[] resources = getDefaultResources(); 587 for( int i=0; i<resources.length; i++ ) 588 { 589 DefaultResource resource = resources[i]; 590 if( ref.equals( resource.getName() ) ) 591 { 592 return resource; 593 } 594 } 595 final String error = 596 "The reference to [" 597 + ref 598 + "] within the module [" 599 + getResourcePath() 600 + "] could not be resolved."; 601 throw new InvalidNameException( error ); 602 } 603 } 604 605 DefaultModule getDefaultModule( final String ref ) 606 { 607 if( null == ref ) 608 { 609 throw new NullPointerException( "ref" ); 610 } 611 int n = ref.indexOf( "/" ); 612 if( n == 0 ) 613 { 614 String newRef = ref.substring( 1 ); 615 return getDefaultModule( newRef ); 616 } 617 else if( n > 0 ) 618 { 619 String pre = ref.substring( 0, n ); 620 String post = ref.substring( n+1 ); 621 DefaultModule module = getDefaultModule( pre ); 622 return module.getDefaultModule( post ); 623 } 624 else 625 { 626 DefaultResource resource = null; 627 try 628 { 629 resource = getDefaultResource( ref ); 630 } 631 catch( InvalidNameException e ) 632 { 633 final String error = 634 "The reference to module [" 635 + ref 636 + "] within the module [" 637 + getResourcePath() 638 + "] does not exist."; 639 throw new InvalidNameException( error, e ); 640 } 641 if( resource instanceof DefaultModule ) 642 { 643 return (DefaultModule) resource; 644 } 645 else 646 { 647 final String error = 648 "A reference to module [" 649 + ref 650 + "] within the module [" 651 + getResourcePath() 652 + "] returned a reference to a non-module resource."; 653 throw new InvalidNameException( error ); 654 } 655 } 656 } 657 658 DefaultModule[] getDefaultModules() 659 { 660 ArrayList stack = new ArrayList(); 661 DefaultResource[] resources = getDefaultResources(); 662 for( int i=0; i<resources.length; i++ ) 663 { 664 DefaultResource resource = resources[i]; 665 if( resource instanceof DefaultModule ) 666 { 667 stack.add( resource ); 668 } 669 } 670 return (DefaultModule[]) stack.toArray( new DefaultModule[0] ); 671 } 672 673 DefaultModule[] getAllDefaultModules() 674 { 675 return getAllDefaultModules( true, false ); 676 } 677 678 DefaultModule[] getAllDefaultModules( final boolean sort, final boolean self ) 679 { 680 if( sort ) 681 { 682 DefaultModule[] modules = getAllDefaultModules( false, self ); 683 return sortDefaultModules( modules ); 684 } 685 else 686 { 687 DefaultModule[] modules = getDefaultModules(); 688 ArrayList visited = new ArrayList(); 689 ArrayList stack = new ArrayList(); 690 for( int i=0; i<modules.length; i++ ) 691 { 692 DefaultModule module = modules[i]; 693 collectChildModules( visited, stack, module ); 694 } 695 if( self ) 696 { 697 stack.add( this ); 698 } 699 return (DefaultModule[]) stack.toArray( new DefaultModule[0] ); 700 } 701 } 702 703 private void collectChildModules( 704 final List visited, final List stack, final DefaultModule module ) 705 { 706 if( visited.contains( module ) ) 707 { 708 return; 709 } 710 visited.add( module ); 711 DefaultModule[] children = module.getDefaultModules(); 712 for( int i=0; i<children.length; i++ ) 713 { 714 collectChildModules( visited, stack, children[i] ); 715 } 716 stack.add( module ); 717 } 718 719 //---------------------------------------------------------------------------- 720 // Selection logic 721 //---------------------------------------------------------------------------- 722 723 DefaultResource[] selectDefaultResources( final String spec ) 724 { 725 return selectDefaultResources( false, spec ); 726 } 727 728 DefaultResource[] selectDefaultResources( final boolean local, final String spec ) 729 { 730 DefaultResource[] resources = doSelectDefaultResources( false, spec ); 731 if( local ) 732 { 733 return filterProjects( resources ); 734 } 735 else 736 { 737 return resources; 738 } 739 } 740 741 DefaultResource[] doSelectDefaultResources( final boolean wild, final String spec ) 742 { 743 String[] tokens = spec.split( "/" ); 744 if( tokens.length == 0 ) 745 { 746 return new DefaultResource[0]; 747 } 748 else if( tokens.length == 1 ) 749 { 750 String token = tokens[0]; 751 if( "**".equals( token ) ) 752 { 753 return getAllDefaultModules( true, !m_root ); 754 } 755 else if( "*".equals( token ) ) 756 { 757 if( wild && !m_root ) 758 { 759 DefaultResource[] resources = getDefaultResources(); 760 DefaultResource[] result = new DefaultResource[ resources.length + 1 ]; 761 System.arraycopy( resources, 0, result, 0, resources.length ); 762 result[ resources.length ] = this; 763 return result; 764 } 765 else 766 { 767 return getDefaultResources(); 768 } 769 } 770 else 771 { 772 Pattern pattern = createSelectionPattern( token ); 773 DefaultResource[] resources = getDefaultResources(); 774 DefaultResource[] selection = selectUsingPattern( resources, pattern ); 775 return selection; 776 } 777 } 778 else 779 { 780 String token = tokens[0]; 781 boolean wildcard = ( token.indexOf( "**" ) > -1 ); 782 String remainder = getRemainderOfSelection( spec, "/", token ); 783 DefaultModule[] modules = selectDefaultModules( token ); 784 ArrayList list = new ArrayList(); 785 for( int i=0; i<modules.length; i++ ) 786 { 787 DefaultModule module = modules[i]; 788 DefaultResource[] selection = module.doSelectDefaultResources( wildcard, remainder ); 789 aggregate( list, selection ); 790 } 791 if( wildcard ) 792 { 793 DefaultResource[] selection = doSelectDefaultResources( wildcard, remainder ); 794 aggregate( list, selection ); 795 } 796 return (DefaultResource[]) list.toArray( new DefaultResource[0] ); 797 } 798 } 799 800 DefaultModule[] selectDefaultModules( final String token ) 801 { 802 if( "**".equals( token ) ) 803 { 804 return getAllDefaultModules( true, !m_root ); 805 } 806 else if( "*".equals( token ) ) 807 { 808 return getDefaultModules(); 809 } 810 else 811 { 812 Pattern pattern = createSelectionPattern( token ); 813 DefaultModule[] modules = getDefaultModules(); 814 DefaultResource[] selection = selectUsingPattern( modules, pattern ); 815 DefaultModule[] result = new DefaultModule[ selection.length ]; 816 for( int i=0; i<selection.length; i++ ) 817 { 818 result[i] = (DefaultModule) selection[i]; 819 } 820 return result; 821 } 822 } 823 824 private DefaultResource[] selectUsingPattern( final DefaultResource[] resources, final Pattern pattern ) 825 { 826 ArrayList list = new ArrayList(); 827 for( int i=0; i<resources.length; i++ ) 828 { 829 Resource resource = resources[i]; 830 String name = resource.getName(); 831 Matcher matcher = pattern.matcher( name ); 832 boolean matches = matcher.matches(); 833 if( matches ) 834 { 835 list.add( resource ); 836 } 837 } 838 return (DefaultResource[]) list.toArray( new DefaultResource[0] ); 839 } 840 841 private String getRemainderOfSelection( final String spec, final String delimiter, final String token ) 842 { 843 int n = token.length() + delimiter.length(); 844 return spec.substring( n ); 845 } 846 847 private void aggregate( final List list, final DefaultResource[] resources ) 848 { 849 for( int i=0; i<resources.length; i++ ) 850 { 851 DefaultResource resource = resources[i]; 852 if( !list.contains( resource ) ) 853 { 854 list.add( resources[i] ); 855 } 856 } 857 } 858 859 private Pattern createSelectionPattern( final String token ) 860 { 861 StringBuffer buffer = new StringBuffer(); 862 boolean wildcard = ( token.indexOf( "*" ) > -1 ); 863 if( wildcard ) 864 { 865 String[] blocks = token.split( "\\*", -1 ); 866 buffer.append( "(" ); 867 for( int j=0; j<blocks.length; j++ ) 868 { 869 buffer.append( "\\Q" ); 870 buffer.append( blocks[j] ); 871 buffer.append( "\\E" ); 872 if( j < ( blocks.length-1 ) ) 873 { 874 buffer.append( ".*" ); 875 } 876 } 877 buffer.append( ")" ); 878 } 879 else 880 { 881 buffer.append( "(\\Q" ); 882 buffer.append( token ); 883 buffer.append( "\\E)" ); 884 } 885 String expression = buffer.toString(); 886 return Pattern.compile( expression ); 887 } 888 889 //---------------------------------------------------------------------------- 890 // Module sorting 891 //---------------------------------------------------------------------------- 892 893 private DefaultModule[] sortDefaultModules( final DefaultModule[] modules ) 894 { 895 Scope scope = Scope.TEST; 896 ArrayList visited = new ArrayList(); 897 ArrayList stack = new ArrayList(); 898 for( int i=0; i<modules.length; i++ ) 899 { 900 DefaultModule module = modules[i]; 901 module.sortDefaultResource( visited, stack, scope, modules ); 902 } 903 return (DefaultModule[]) stack.toArray( new DefaultModule[0] ); 904 } 905 906 /** 907 * Returns a sorted array of the provider modules this this module depends on. 908 * The notion of dependency is ressolved via (a) direct depedencies declared 909 * by the module, (b) subsidiary module which are considered as sippliers to 910 * this module, and (c) module referenced by any resources contained within 911 * this or any subsidiary module. 912 */ 913 private DefaultModule[] getProviderModules( final Scope scope ) 914 { 915 ArrayList visited = new ArrayList(); 916 ArrayList stack = new ArrayList(); 917 processModuleDependencies( visited, stack, scope, this ); 918 return (DefaultModule[]) stack.toArray( new DefaultModule[0] ); 919 } 920 921 private void processModuleDependencies( 922 final List visited, final List stack, final Scope scope, final DefaultResource resource ) 923 { 924 if( visited.contains( resource ) ) 925 { 926 return; 927 } 928 929 visited.add( resource ); 930 final boolean expansion = false; 931 final boolean filtering = false; 932 933 Classifier classifier = resource.getClassifier(); 934 if( classifier.equals( Classifier.ANONYMOUS ) ) 935 { 936 return; 937 } 938 939 if( resource instanceof DefaultModule ) 940 { 941 DefaultModule module = (DefaultModule) resource; 942 DefaultResource[] providers = module.getAggregatedDefaultProviders( scope, expansion, filtering ); 943 for( int i=0; i<providers.length; i++ ) 944 { 945 processModuleDependencies( visited, stack, scope, providers[i] ); 946 } 947 DefaultResource[] children = module.getDefaultModules(); 948 for( int i=0; i<children.length; i++ ) 949 { 950 processModuleDependencies( visited, stack, scope, children[i] ); 951 } 952 if( !resource.equals( this ) ) 953 { 954 stack.add( module ); 955 } 956 } 957 else 958 { 959 DefaultResource[] resources = 960 resource.getAggregatedDefaultProviders( scope, expansion, filtering ); 961 for( int i=0; i<resources.length; i++ ) 962 { 963 DefaultModule m = resources[i].getDefaultParent(); 964 processModuleDependencies( visited, stack, scope, m ); 965 } 966 } 967 } 968 969 private DefaultResource[] filterProjects( final DefaultResource[] resources ) 970 { 971 ArrayList list = new ArrayList(); 972 for( int i=0; i<resources.length; i++ ) 973 { 974 DefaultResource resource = resources[i]; 975 if( resource.isLocal() ) 976 { 977 list.add( resource ); 978 } 979 } 980 return (DefaultResource[]) list.toArray( new DefaultResource[0] ); 981 } 982 }